package kgc.crm.config;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class StringToEnumConverterFactory implements ConverterFactory<String, Enum<?>> {
    //01.定义用来存储被实例化出来的枚举类型
    private static final Map<Class<?>, Converter<String, ? extends Enum<?>>> CONVERTER_MAP = new ConcurrentHashMap<>();

    @Override
    @SuppressWarnings("unchecked cast")
    public <T extends Enum<?>> Converter<String, T> getConverter(Class<T> targetType) {
        // 缓存转换器 String 类型存的是 前端传递过来的 字符串类型数字，T则是泛型的枚举构造
        //CONVERTER_MAP.get(targetType) 会先在已经定义好的MAP中去寻找是否已经被实例化过，如果已经被实例化，则不在执行IF操作
        Converter<String, T> converter = (Converter<String, T>) CONVERTER_MAP.get(targetType);
        if (converter == null) {
            //调用内部类中的StringToEnumConverter方法去将 targetType 类型的枚举构造进行实例化
            converter = new StringToEnumConverter<>(targetType);
            //将构建好所有构造方法的 枚举MAP集合传入到 CONVERTER_MAP 当中，targetType则为KEY值，SpringBoot 会根据targetType去找到对应 converter 进行构造调用并进行转换
            CONVERTER_MAP.put(targetType, converter);
        }
        return converter;
    }

    static class StringToEnumConverter<T extends Enum<?>> implements Converter<String, T> {
        //用来存储构建出的 枚举类型的所有构造
        private final Map<String, T> enumMap = new ConcurrentHashMap<>();

        StringToEnumConverter(Class<T> enumType) {
            Method method = getMethod(enumType);
            T[] enums = enumType.getEnumConstants();

            // 将值与枚举对象对应并缓存
            for (T e : enums) {
                try {
                    enumMap.put(method.invoke(e).toString(), e);
                } catch (IllegalAccessException | InvocationTargetException ex) {
                    log.error("获取枚举值错误!!! ", ex);
                }
            }
        }


        @Override
        public T convert(@NotNull String source) {
            // 获取
            T t = enumMap.get(source);
            if (t == null) {
                throw new IllegalArgumentException("该字符串找不到对应的枚举对象 字符串:" + source);
            }
            return t;
        }
    }

    public static <T> Method getMethod(Class<T> enumType) {
        Method method;
        // 找到取值的方法
        try {
            method = enumType.getMethod("getValue");
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException(String.format("类:%s 找不到 getValue方法",
                    enumType.getName()));
        }
        return method;
    }


    private static Optional<Field> dealEnumType(Class<?> clazz) {
        return clazz.isEnum() ?
                Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.isAnnotationPresent(EnumValue.class)).findFirst() : Optional.empty();
    }
}